#include "rasterScanAPI.h"




/* ------------------------ Public Methods ------------------------ */

void i_initRasterScan(char * rasterScanFileName)
{
  
  FILE *fptr;        /* file pointer that holds image */

  printf("Initializing a Raster Scan...\n");
  
  /* open image */
  if((fptr = fopen(rasterScanFileName, "r")) == NULL)
  {
    /* did not open file */
    printf("ERROR IN OPENING FILE\n");
    return;
  }

  /* save name of image */
  strcpy(rsImage.name,rasterScanFileName);

  /* get first string of file */
  fscanf(fptr,"%s",buf);

  /* checking for correct file format */
  /* TODO: make this account for all .pnm file types */
  if (buf[1] == '1') 
  {
    /* find the end of this row, preventative */
    fscanf(fptr,"%s",buf);
    while (buf[0] != '\n') fscanf(fptr,"%c",&buf[0]);
  }
  else
  {
    printf("ERROR NOT A .pbn FILE\n");
    return;
  }

  /* Get image size */
  fscanf(fptr,"%d %d\n",&(rsImage.ncols),&(rsImage.nrows));

  /* allocate memory for the pixel matrix */
  rsImage.rawImage = rasterScanAllocateMatrix(rsImage.nrows,rsImage.ncols);

  /* load matrix with individual pixel values */
  for(loopCountX = 0; loopCountX < rsImage.nrows; loopCountX++)
  {
    
    for(loopCountY = 0; loopCountY < rsImage.ncols; loopCountY++)
    {

      /* get next character, since we are working with ascii .pbn file */
      fscanf(fptr,"%c",buf);

      /* filter out carriage return */
      if(0x0A == *buf) fscanf(fptr,"%c",buf);

      /* load matrix with individual characters */
      rsImage.rawImage[loopCountX][loopCountY] = *buf;

    }

  }

  /* close file, we don't need it anymore */
  fclose(fptr);

}


void i_startAutoRasterScan(RASTERSCANDISPLAYTYPE rasterScanDisplayType)
{
  
  switch (rasterScanDisplayType)
  {
    case RASTERSCAN_NO_DISPLAY:

      /* to be filled out later */
      break;

    case RASTERSCAN_DISPLAY_END:

      printAnimation = 0;

      break;

    case RASTERSCAN_DISPLAY_RASTERSCAN_ANIMATION:

      printAnimation = 1;

      /* to be filled out later */
      break;

    default:

      /* error trap */
      break;

  }

  rasterScan();

}


void i_printRasterScanMatrix(void)
{
  int x, y;

  /* loop through 2d array for printing */
  for(x = 0; x < rsImage.nrows; x++)
  {
    for(y = 0; y < rsImage.ncols; y++)
    {

      /* sniff out white areas of image */
      if('0' == rsImage.rawImage[x][y])
      {

        /* white area is printed with an '-', instead of '0' for
         * better visual viewing on terminal */
        printf("- ");

      }
      else
      {

        /* print label associated with black part of image */
        printf("%c ",rsImage.rawImage[x][y]);

      }
    }

    printf("\n");

  }

  printf("\n\n");

}

void ucmtxfree2(unsigned char **matrix,int m,int n)
{
   int i;
   for(i=0;i<m;i++)
     free(matrix[i]);
   free(matrix);
}

void i_deallocRasterScan(void)
{

  unsigned int interval;

  for(interval = 0; interval < rsImage.nrows; interval++)
  {
    free(rsImage.rawImage[interval]);
  }

  free(rsImage.rawImage);

}

void rasterScan(void)
{
  unsigned int maxIntervalCount;
  unsigned int rasterScanCheck;
  unsigned int (*rasterScanChecks[])(void) = {rasterScanCheckOne,
                                              rasterScanCheckTwo,
                                              rasterScanCheckThree,
                                              rasterScanCheckFour};

  printf("Start Raster Scan...\n");
  currentLabel = 'A';

  /* First Pass Algorithm Rows */
  for(loopCountX = 0; loopCountX < rsImage.nrows; loopCountX++)
  {
    for(loopCountY = 0; loopCountY < rsImage.ncols; loopCountY++)
    {
      if('0' != rsImage.rawImage[loopCountX][loopCountY])
      {
        for(rasterScanCheck = 0; rasterScanCheck < 4; rasterScanCheck++)
        {

          /* Go through Raster Scan Checks, and Exit if One is True */
          if(rasterScanChecks[rasterScanCheck] ()) break;

        }
        if(printAnimation) printRasterScanMatrix();
      }
    }
  }


  for(maxIntervalCount = 0; maxIntervalCount < MAXINTERVAL; maxIntervalCount++)
  {

    /* clear fix count */
    pixelFixCount = 0;

    /* First Pass Algorithm Columns */
    for(loopCountY = 0; loopCountY < rsImage.ncols; loopCountY++)
    {
      for(loopCountX = 0; loopCountX < rsImage.nrows; loopCountX++)
      {
        if('0' != rsImage.rawImage[loopCountX][loopCountY])
        {

           rasterScanCheckFive();

        }
      }
    }

    /* check to see if all fixes are in place */
    if(!pixelFixCount) break;

    if(maxIntervalCount == (MAXINTERVAL - 1)) printf("MAX INTERVAL HIT!!!\n");

  }
}
        



unsigned int rasterScanCheckOne(void)
{

  /* Check for a Boundary Condition, loopCountX == 0 */
  /* Check Pixel to the 'west' of the current pixel */
  if(isWestPositive() && loopCountX)
  {
    /* set current pixel label to 'west' pixel label */
    setCurrentEqualToWest();

    /* TODO: Verify if we need to check rasterScanCheckTwo */
    rasterScanCheckTwo();

    /* Check TRUE */
    return 1;
  }

  /* Check FALSE */
  return 0;

}

unsigned int rasterScanCheckTwo(void)
{
  /* Check for Boundary Condtions */
  if(isNorthPositive() && loopCountY)
  {
    /* Need to filter x boundaries */
    if(isWestPositive() && loopCountX )
    {
      /* Check to see if the items ar not equal */
      if(WestPixelValue != NorthPixelValue)
      {
        /* Check to see if 'west' is greater than the 'north' */
        if(WestPixelValue > NorthPixelValue)
        {
          /* Set 'west' equal to the 'north' */
          WestPixelValue = NorthPixelValue;
          /* Set 'current' equal to the 'north' */
          CurrentPixelValue = NorthPixelValue;
        }
        else
        {
          /* Set 'Current' equal to the 'west' */
          CurrentPixelValue = WestPixelValue;
          /* Set 'north' equal to the 'west' */
          NorthPixelValue = WestPixelValue;
        }
      }
      else
      {
        /* Set 'Current' equal to the 'west' */
        CurrentPixelValue = WestPixelValue;
      }
    }
    else
    {
      /* Set 'current' equal to the 'north' */
      CurrentPixelValue = NorthPixelValue;
    }
    return 1;
  }
  /* Returning 0 since CheckOne should have caught the 'west' match */
  return 0;
}

unsigned int rasterScanCheckThree(void)
{
  /* Does not have help on a binary image */
  return 0;
}

unsigned int rasterScanCheckFour(void)
{
  if('1' == CurrentPixelValue)
  {
    CurrentPixelValue = currentLabel++;
  }
  return 1;
}

unsigned int rasterScanCheckFive(void)
{
  /* take care of 'west' comparison to 'current' pixel */
  if(westCrossCheck()) pixelFixCount++;
  /* take care of 'north' comparison to 'current' pixel */
  if(northCrossCheck()) pixelFixCount++;
  return 1;
}

void setCurrentEqualToWest(void)
{
  /* no protection here, use wisely */
  CurrentPixelValue = WestPixelValue;
}

unsigned int northCrossCheck(void)
{
  /* take care of 'north' comparison to 'current' pixel */
  if(('0' != NorthPixelValue) && loopCountY)
  {
    /* are pixels equal */
    if(CurrentPixelValue != NorthPixelValue)
    {

      if(CurrentPixelValue < NorthPixelValue)
      {
        NorthPixelValue = CurrentPixelValue;
      }
      else
      {
        CurrentPixelValue = NorthPixelValue;
      }
      return 1;
    }
  }
  return 0;
}

unsigned int westCrossCheck(void)
{
  /* take care of 'west' comparison to 'current' pixel */
  if(('0' != WestPixelValue) && loopCountX)
  {
    if(CurrentPixelValue != WestPixelValue)
    {

      /* Need to nest both x edge and '0' */
      if(CurrentPixelValue < WestPixelValue)
      {
        WestPixelValue = CurrentPixelValue;
      }
      else
      {
        CurrentPixelValue = WestPixelValue;
      }
      return 1;
    }
  }
  return 0;
}

unsigned char **rasterScanAllocateMatrix(int length, int height)
{
   unsigned char **matrix;
   int i;
   
   /* allocate memory for the for the pointers of each row */
   matrix = (unsigned char **)malloc(sizeof(unsigned char *) * length);

   for(i = 0; i < length; i++)
   {
     
     /* allocate memory for the column positions in each row */
     matrix[i]= (unsigned char *) calloc(height, sizeof(unsigned char));

   }

   return(matrix);

}

